/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
/**
 * Software License, Version 1.0
 *
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 *
 *
 *Redistribution and use in source and binary forms, with or without
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For
 * further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and
 * wherever such third-party acknowledgments normally appear.
 *
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering,
 * shall not be used to endorse or promote products derived from this software
 * without prior written permission from Indiana University.  For written
 * permission, please contact the Advanced Research and Technology Institute
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering,
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 *
 *
 * Indiana University provides no reassurances that the source code provided
 * does not infringe the patent or any other intellectual property rights of
 * any other entity.  Indiana University disclaims any liability to any
 * recipient for claims brought by any other entity based on infringement of
 * intellectual property rights or otherwise.
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.service.time.ntptime;

import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Date;

/**
 * This class provides some methods to make UDP connection, send/receive NTP
 * packets
 *
 * @author Hasan Bulut - hbulut@indiana.edu
 */
public class NtpConnection {
  //~ Static fields/initializers -----------------------------------------------

  public static final int defaultNtpPort = 123;

  //~ Instance fields ----------------------------------------------------------

  TimeServiceImpl        tsi       = TimeServiceImpl.getInstance();
  private DatagramSocket ntpSocket;
  private InetAddress    ntpServer;
  private int            ntpPort;
  private int            timeout = 500;

  //~ Constructors -------------------------------------------------------------

  /**
   * Generates a UDP connection and sets timeout to the socket
   *
   * @param iaddr InetAddress - InetAddress of the server
   * @param iport int - port number of the server
   * @throws SocketException - SocketException is thrown in case of failure
   */
  public NtpConnection(InetAddress iaddr, int iport) throws SocketException {
    ntpServer = iaddr;
    ntpPort   = iport;
    ntpSocket = new DatagramSocket();
    ntpSocket.setSoTimeout(timeout);
  }

  /**
   * Generates a UDP connection and sets the timeout to the default timeout value.
   * @param iaddr InetAddress - InetAddress of the server
   * @throws SocketException - SocketException is thrown in case of failure
   */
  public NtpConnection(InetAddress iaddr) throws SocketException {
    ntpServer = iaddr;
    ntpPort   = defaultNtpPort;
    ntpSocket = new DatagramSocket();
    ntpSocket.setSoTimeout(timeout);
  }

  //~ Methods ------------------------------------------------------------------

  /**
   * Sets buffer entries from start to end-1 with the given data array
   *
   * @param start int - start value
   * @param end int - end value
   * @param tbuffer byte[] - buffer
   * @param data byte[] - data array to be copied
   */
  public void setBuffer(int start, int end, byte[] tbuffer, byte[] data) {
    if (tbuffer.length >= end) {
      for (int i = start; i < end; i++) {
        tbuffer[i] = data[i - start];
      }
    }
  }

  /**
   * Exchanges NtpDatagramPacket with the server and generates NtpInfo object.
   * @return NtpInfo - NtpInfo object obtained from NTPDatagramPacket
   * @throws IOException - IOException is thrown in case of socket timeout or connection failure
   */
  public NtpInfo getInfo() throws IOException {
    NtpInfo           ntpInfo   = new NtpInfo();
    NtpDatagramPacket dpReceive = new NtpDatagramPacket();
    NtpDatagramPacket dpSend    = new NtpDatagramPacket(ntpServer, ntpPort);
    send(dpSend);
    receive(dpReceive);
    ntpInfo = dpReceive.getInfo();
    return ntpInfo;
  }

  /**
   * This method is intended to be used with ClientDiscrepancy class. Please do
   * not use for other purposes. Returns NtpInfo.
   * @return NtpInfo
   *
   * @throws IOException
   */
  public NtpInfo getTSInfo() throws IOException {
    NtpInfo      ntpInfo    = new NtpInfo();
    NtpTimestamp transmitTS = new NtpTimestamp();
    long         offset1    = tsi.getOffset();
    transmitTS.setTimestamp(new Date((new Date()).getTime() + offset1));
    NtpDatagramPacket dpReceive = new NtpDatagramPacket();
    NtpDatagramPacket dpSend = new NtpDatagramPacket(ntpServer, ntpPort);
    setBuffer(NtpOffset.offTransmitTimestamp, NtpOffset.NTPDataLength,
              dpSend.getDatagramPacket().getData(),
              transmitTS.getTimestampData());
    send(dpSend);
    receiveTS(dpReceive, offset1);
    ntpInfo = dpReceive.getInfo();
    return ntpInfo;
  }

  /**
   * Sets the timeout of the asociated connection.
   * @param timeout int - value of the timeout
   * @throws SocketException - SocketException is thrown in case of connection failure
   */
  public void setTimeout(int timeout) throws SocketException {
    this.timeout = timeout;
    ntpSocket.setSoTimeout(timeout);
  }

  /**
   * Gets the timeout of the connection. The default timeout
   * is 500 ms.
   * @return int - timeout value
   */
  public int getTimeout() {
    return timeout;
  }

  /**
   * Closes the connection.
   */
  public void close() {
    ntpSocket.close();
  }

  /**
   * Waits for a reply from the server.
   * @param ntpDatagramPacket NtpDatagramPacket - NtpDatagramPacket that will be
   * set to the NtpDatagramPacket received from the server.
   * @throws IOException - IOException is thrown in case of socket timeout or connection failure
   */
  public void receive(NtpDatagramPacket ntpDatagramPacket)
               throws IOException {
    ntpSocket.receive(ntpDatagramPacket.getDatagramPacket());
    ntpDatagramPacket.setReceptionTimeStamp(new NtpTimestamp());
  }

  /**
   * This method is intended to be used with ClientDiscrepancy class. Please do
   * not use for other purposes. Receives NtpDatagramPacket and timestamps it
   * with the adjusted time value.
   * @param ntpDatagramPacket
   * @param offset11 long - offset
   *
   * @throws IOException
   */
  public void receiveTS(NtpDatagramPacket ntpDatagramPacket, long offset11)
                 throws IOException {
    ntpSocket.receive(ntpDatagramPacket.getDatagramPacket());
    NtpTimestamp ts = new NtpTimestamp();
    ts.setTimestamp(new Date((new Date()).getTime() + offset11));
    ntpDatagramPacket.setReceptionTimeStamp(ts);
  }

  /**
   * Sends NtpDatagramPacket to the server.
   * @param ntpDatagramPacket NtpDatagramPacket - NtpDatagramPacket that will be
   * sent to the server.
   * @throws IOException - IOException is thrown in case of connection failure
   */
  public void send(NtpDatagramPacket ntpDatagramPacket)
            throws IOException {
    ntpSocket.send(ntpDatagramPacket.getDatagramPacket());
  }
}
